// // 磁盘级blockgroup的数据结构
// /*
//  * Structure of a blocks group descriptor
//  */
// struct ext2_group_desc
// {
//     __le32 bg_block_bitmap;      /* Blocks bitmap block */
//     __le32 bg_inode_bitmap;      /* Inodes bitmap */
//     __le32 bg_inode_table;       /* Inodes table block*/
//     __le16 bg_free_blocks_count; /* Free blocks count */
//     __le16 bg_free_inodes_count; /* Free inodes count */
//     __le16 bg_used_dirs_count;   /* Directories count */
//     __le16 bg_pad;
//     __le32 bg_reserved[3];
// };

// /*
//  * Structure of the super block
//  */
// struct ext2_super_block
// {
//     -----------------------------
//     __le32 s_inodes_count;      /* Inodes count */
//     __le32 s_blocks_count;      /* Blocks count */
//     -----------------------------
//     __le32 s_r_blocks_count;    /* Reserved blocks count */
//     -----------------------------
//     __le32 s_free_blocks_count; /* Free blocks count */
//     __le32 s_free_inodes_count; /* Free inodes count */
//     __le32 s_first_data_block;  /* First Data Block */
//     -----------------------------
//     __le32 s_log_block_size;    /* Block size */
//     __le32 s_log_frag_size;     /* Fragment size */
//     -----------------------------
//     __le32 s_blocks_per_group;  /* # Blocks per group */
//     -----------------------------
//     __le32 s_frags_per_group;   /* # Fragments per group */
//     -----------------------------
//     __le32 s_inodes_per_group;  /* # Inodes per group */
//     __le32 s_mtime;             /* Mount time */
//     __le32 s_wtime;             /* Write time */
//     __le16 s_mnt_count;         /* Mount count */
//     __le16 s_max_mnt_count;     /* Maximal mount count */
//     __le16 s_magic;             /* Magic signature */
//     __le16 s_state;             /* File system state */
//     __le16 s_errors;            /* Behaviour when detecting errors */
//     __le16 s_minor_rev_level;   /* minor revision level */
//     __le32 s_lastcheck;         /* time of last check */
//     __le32 s_checkinterval;     /* max. time between checks */
//     __le32 s_creator_os;        /* OS */
//     __le32 s_rev_level;         /* Revision level */
//     __le16 s_def_resuid;        /* Default uid for reserved blocks */
//     __le16 s_def_resgid;        /* Default gid for reserved blocks */
//     /*
//     * These fields are for EXT2_DYNAMIC_REV superblocks only.
//     * *
//     Note: the difference between the compatible feature set and
//     * the incompatible feature set is that if there is a bit set
//     * in the incompatible feature set that the kernel doesn't
//     * know about, it should refuse to mount the filesystem.
//     * *
//     e2fsck's requirements are more strict; if it doesn't know
//     * about a feature in either the compatible or incompatible
//     * feature set, it must abort and not try to meddle with
//     * things it doesn't understand...
//     */
//     __le32 s_first_ino;              /* First non-reserved inode */
//     __le16 s_inode_size;             /* size of inode structure */
//     __le16 s_block_group_nr;         /* block group # of this superblock */
//     __le32 s_feature_compat;         /* compatible feature set */
//     __le32 s_feature_incompat;       /* incompatible feature set */
//     __le32 s_feature_ro_compat;      /* readonly-compatible feature set */
//     __u8 s_uuid[16];                 /* 128-bit uuid for volume */
//     char s_volume_name[16];          /* volume name */
//     char s_last_mounted[64];         /* directory where last mounted */
//     __le32 s_algorithm_usage_bitmap; /* For compression */
//     /*
//      * Performance hints. Directory preallocation should only
//      * happen if the EXT2_COMPAT_PREALLOC flag is on.
//      */
//     __u8 s_prealloc_blocks;     /* Nr of blocks to try to preallocate*/
//     __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
//     __u16 s_padding1;
//     /*
//      * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
//      */
//     __u8 s_journal_uuid[16]; /* uuid of journal superblock */
//     __u32 s_journal_inum;    /* inode number of journal file */
//     __u32 s_journal_dev;     /* device number of journal file */
//     __u32 s_last_orphan;     /* start of list of inodes to delete */
//     __u32 s_hash_seed[4];    /* HTREE hash seed */
//     __u8 s_def_hash_version; /* Default hash version to use */
//     __u8 s_reserved_char_pad;
//     __u16 s_reserved_word_pad;
//     __le32 s_default_mount_opts;
//     __le32 s_first_meta_bg; /* First metablock block group */
//     __u32 s_reserved[190];  /* Padding to the end of the block */
// }

// /*
//  * Structure of an inode on the disk
//  */
// struct ext2_inode
// {
//     __le16 i_mode;        /* File mode */
//     __le16 i_uid;         /* Low 16 bits of Owner Uid */
//     __le32 i_size;        /* Size in bytes */
//     __le32 i_atime;       /* Access time */
//     __le32 i_ctime;       /* Creation time */
//     __le32 i_mtime;       /* Modification time */
//     __le32 i_dtime;       /* Deletion Time */
//     __le16 i_gid;         /* Low 16 bits of Group Id */
//     __le16 i_links_count; /* Links count */
//     __le32 i_blocks;      /* Blocks count */
//     __le32 i_flags;       /* File flags */
//     union
//     {
//         struct
//         {
//             __le32 l_i_reserved1;
//         } linux1;
//         struct
//         {
//             __le32 h_i_translator;
//         } hurd1;
//         struct
//         {
//             __le32 m_i_reserved1;
//         } masix1;
//     } osd1;                        /* OS dependent 1 */
//     __le32 i_block[EXT2_N_BLOCKS]; /* Pointers to blocks */
//     __le32 i_generation;           /* File version (for NFS) */
//     __le32 i_file_acl;             /* File ACL */
//     __le32 i_dir_acl;              /* Directory ACL */
//     __le32 i_faddr;                /* Fragment address */
//     union
//     {
//         struct
//         {
//             __u8 l_i_frag;  /* Fragment number */
//             __u8 l_i_fsize; /* Fragment size */
//             __u16 i_pad1;
//             __le16 l_i_uid_high; /* these 2 fields */
//             __le16 l_i_gid_high; /* were reserved2[0] */
//             __u32 l_i_reserved2;
//         } linux2;
//         struct
//         {
//             __u8 h_i_frag;  /* Fragment number */
//             __u8 h_i_fsize; /* Fragment size */
//             __le16 h_i_mode_high;
//             __le16 h_i_uid_high;
//             __le16 h_i_gid_high;
//             __le32 h_i_author;
//         } hurd2;
//         struct
//         {
//             __u8 m_i_frag;  /* Fragment number */
//             __u8 m_i_fsize; /* Fragment size */
//             __u16 m_pad1;
//             __u32 m_i_reserved2[2];
//         } masix2;
//     } osd2; /* OS dependent 2 */
// };

// #include <stdio.h>
// #include <string.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// #include <unistd.h>
// int main()
// {
//     close(2);
//     int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//     if (fd < 0)
//     {
//         perror("open");
//         return 0;
//     }
//     perror("hello world");
//     close(fd);
//     return 0;
// }

// #include <stdio.h>
// #include <string.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// #include <unistd.h>
// int main()
// {
//     close(1);
//     int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//     if (fd < 0)
//     {
//         perror("open");
//         return 0;
//     }
//     printf("hello world: %d\n", fd);
//     fflush(stdout) ;
//     close(fd);
//     return 0;
// }

// struct file_operations
// {
//     struct module *owner;
//     // 指向拥有该模块的指针；
//     loff_t (*llseek)(struct file *, loff_t, int);
//     // llseek ⽅法⽤作改变⽂件中的当前读/写位置, 并且新位置作为(正的)返回值.
//     ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
//     // ⽤来从设备中获取数据. 在这个位置的⼀个空指针导致 read 系统调⽤以 -
//     EINVAL("Invalid argument")
//     失败.⼀个⾮负返回值代表了成功读取的字节数(返回值是⼀个
//                                               "signed size" 类型,
//                                               常常是⽬标平台本地的整数类型)
//         .ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
//     // 发送数据给设备. 如果 NULL, -EINVAL 返回给调⽤ write 系统调⽤的程序. 如果⾮负, 返回值代表成功写的字节数.
//     ssize_t (*aio_read)(struct kiocb *, const struct iovec *, unsigned long,
//                         loff_t);
//     // 初始化⼀个异步读 -- 可能在函数返回前不结束的读操作.
//     ssize_t (*aio_write)(struct kiocb *, const struct iovec *, unsigned long,
//                          loff_t);
//     // 初始化设备上的⼀个异步写.
//     int (*readdir)(struct file *, void *, filldir_t);
//     // 对于设备⽂件这个成员应当为 NULL; 它⽤来读取⽬录, 并且仅对**⽂件系统**有⽤.
//     unsigned int (*poll)(struct file *, struct poll_table_struct *);
//     int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
//     long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);
//     long (*compat_ioctl)(struct file *, unsigned int, unsigned long);
//     int (*mmap)(struct file *, struct vm_area_struct *);
//     // mmap ⽤来请求将设备内存映射到进程的地址空间. 如果这个⽅法是 NULL, mmap 系统调⽤返
//     回 - ENODEV.int (*open)(struct inode *, struct file *);
//     // 打开⼀个⽂件
//     int (*flush)(struct file *, fl_owner_t id);
//     // flush 操作在进程关闭它的设备⽂件描述符的拷⻉时调⽤;
//     int (*release)(struct inode *, struct file *);
//     // 在⽂件结构被释放时引⽤这个操作. 如同 open, release 可以为 NULL.
//     int (*fsync)(struct file *, struct dentry *, int datasync);
//     // ⽤⼾调⽤来刷新任何挂着的数据.
//     int (*aio_fsync)(struct kiocb *, int datasync);
//     int (*fasync)(int, struct file *, int);
//     int (*lock)(struct file *, int, struct file_lock *);
//     // lock ⽅法⽤来实现⽂件加锁; 加锁对常规⽂件是必不可少的特性, 但是设备驱动⼏乎从不实现它.
//     ssize_t (*sendpage)(struct file *, struct page *, int, size_t, loff_t *,
//                         int);
//     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
//     int (*check_flags)(int);
//     int (*flock)(struct file *, int, struct file_lock *);
//     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
//                             size_t, unsigned int);
//     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
//                            size_t, unsigned int);
//     int (*setlease)(struct file *, long, struct file_lock **);
// };

// struct file
// {
//     ...

//     struct inode *f_inode; /* cached value */
//     const struct file_operations *f_op;

//     ...

//     atomic_long_t f_count;                      // 表⽰打开⽂件的引⽤计数，如果有多个⽂件指针指向它，就会增加f_count的值。 unsigned int f_flags; // 表⽰打开⽂件的权限
//     fmode_t f_mode;                                 // 设置对⽂件的访问模式,例如：只读，只写等。所有的标志在头⽂件<fcntl.h> 中定义
//     loff_t f_pos; // 表⽰当前读写⽂件的位置

//     ...

// } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */

// #include <stdio.h>
// #include <unistd.h>
// #include <fcntl.h>
// int main()
// {
//     //int fd = open("./log", O_RDWR | O_APPEND);
//     int fd = open("./log", O_CREAT | O_RDWR);
//     if (fd < 0)
//     {
//         perror("open");
//         return 1;
//     }
//     close(1);
//     dup2(fd, 1);
//     for (;;)
//     {
//         char buf[1024] = {0};
//         ssize_t read_size = read(0, buf, sizeof(buf) - 1);
//         if (read_size < 0)
//         {
//             perror("read");
//             break;
//         }
//         printf("%s", buf);
//         fflush(stdout);
//     }
//     return 0;
// }

// #include <stdio.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// #include <stdlib.h>
// int main()
// {
//     //close(1);
//     //当我们关闭标准输出，此时不会打印到屏幕上，而是由文件占据1这个文件标识符
//     int fd = open("myfile", O_WRONLY | O_CREAT, 00644);
//     if (fd < 0)
//     {
//         perror("open");
//         return 1;
//     }
//     printf("fd: %d\n", fd);//会向1文件标识符打印，此时就会向myfile文本打印
//     fflush(stdout);
//     close(fd);
//     exit(0);
// }

// #include <stdio.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// int main()
// {
//     //close(0);
//     //当我们没有关闭标识符0，返回3。
//     //当我们关闭标识符0，返回0，
//     //说明标识符的打开是跟随从小到大，最小的优先占据的规则
//     int fd = open("myfile", O_RDONLY);
//     if (fd < 0)
//     {
//         perror("open");
//         return 1;
//     }
//     printf("fd: %d\n", fd);
//     close(fd);
//     return 0;
// }

// #include <stdio.h>
// #include <sys/types.h>
// #include <sys/stat.h>
// #include <fcntl.h>
// #include <string.h>

// int main()
// {
//     char buf[1024];
//     ssize_t s = read(0, buf, sizeof(buf));
//     if (s > 0)
//     {
//         buf[s] = 0;
//         write(1, buf, strlen(buf));
//         write(2, buf, strlen(buf));
//     }
//     return 0;
// }